/*
 *  Copyright 2012 Dirk Vranckaert
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package eu.vranckaert.vvl.activities.trafficinfo;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.*;
import eu.vranckaert.vvl.R;
import eu.vranckaert.vvl.activities.list.adapter.TrafficInfoTextAdapter;
import eu.vranckaert.vvl.exception.ServiceException;
import eu.vranckaert.vvl.exception.webservice.WebServiceException;
import eu.vranckaert.vvl.exception.webservice.WebServiceRequestFailureException;
import eu.vranckaert.vvl.model.TrafficInfoTextEnum;
import eu.vranckaert.vvl.model.TrafficInfoText;
import eu.vranckaert.vvl.service.InformationTextService;
import eu.vranckaert.vvl.service.impl.InformationTextServiceImpl;
import eu.vranckaert.vvl.utils.context.Constants;
import eu.vranckaert.vvl.utils.context.IntentUtil;
import eu.vranckaert.vvl.utils.context.NotificationUtil;
import eu.vranckaert.vvl.utils.context.Preference;
import eu.vranckaert.vvl.utils.view.MultiSelectSpinner;

import java.util.*;

/**
 * User: DIRK VRANCKAERT
 * Date: 16/02/12
 * Time: 12:12
 */
public class TrafficInfoTextActivity extends ListActivity {
    private InformationTextService informationTextService;
    
    private Button loadDataButton;
    private View loadingWheel;
    private View refreshButton;

    private List<TrafficInfoTextEnum.InformationType> informationTypeValues;
    private List<TrafficInfoTextEnum.Region> regionValues;
    private List<TrafficInfoTextEnum.Highroad> highroadValues;
    private List<TrafficInfoTextEnum.SecondaryRoads> secondaryRoadValues;
    
    private List<TrafficInfoTextEnum.InformationType> selectedInformationTypes = new ArrayList<TrafficInfoTextEnum.InformationType>();
    private List<TrafficInfoTextEnum.Region> selectedRegions = new ArrayList<TrafficInfoTextEnum.Region>();
    private List<TrafficInfoTextEnum.Highroad> selectedHighroads = new ArrayList<TrafficInfoTextEnum.Highroad>();
    private List<TrafficInfoTextEnum.SecondaryRoads> selectedSecondaryRoads = new ArrayList<TrafficInfoTextEnum.SecondaryRoads>();
    
    private LoadDataTask loadDataTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.activity_traffic_info_text);

        createService();
        loadViewObjects();
        initializeView();
        attachButtons();

        registerForContextMenu(getListView());

        handleAlarm(getIntent().getExtras());
    }

    private void handleAlarm(Bundle extras) {
        if (extras == null)
            return;

        ArrayList<TrafficInfoTextEnum.InformationType> informationTypes = (ArrayList<TrafficInfoTextEnum.InformationType>) extras.get(Constants.Extra.INFORMATION_TYPES);
        ArrayList<TrafficInfoTextEnum.Region> regions = (ArrayList<TrafficInfoTextEnum.Region>) extras.get(Constants.Extra.REGIONS);
        ArrayList<TrafficInfoTextEnum.Highroad> highroads = (ArrayList<TrafficInfoTextEnum.Highroad>) extras.get(Constants.Extra.HIGHROADS);
        ArrayList<TrafficInfoTextEnum.SecondaryRoads> secondaryRoads = (ArrayList<TrafficInfoTextEnum.SecondaryRoads>) extras.get(Constants.Extra.SECONDARY_ROADS);

        if (informationTypes != null && !informationTypes.isEmpty()) {
            selectedInformationTypes = informationTypes;
        }
        if (regions != null && !regions.isEmpty()) {
            selectedRegions = regions;
        }
        if (highroads != null && !highroads.isEmpty()) {
            selectedHighroads = highroads;
        }
        if (secondaryRoads != null && !secondaryRoads.isEmpty()) {
            selectedSecondaryRoads = secondaryRoads;
        }

        NotificationUtil.getInstance(TrafficInfoTextActivity.this).flashLedLight();
    }

    private void createService() {
        informationTextService = new InformationTextServiceImpl(TrafficInfoTextActivity.this);
    }

    private void loadViewObjects() {
        loadDataButton = (Button) findViewById(R.id.load_info_button);
        loadingWheel = findViewById(R.id.progress_indicator_container);
        refreshButton = findViewById(R.id.refresh_button_container);
    }

    private void initializeView() {
        //InformationType list
        informationTypeValues = Arrays.asList(TrafficInfoTextEnum.InformationType.values());
        Boolean[] defaultInformationValues = new Boolean[informationTypeValues.size()];
        List<TrafficInfoTextEnum.InformationType> selectedInformationTypeValuesPreferences
                = Preference.getSelectedTextInformationTypes(TrafficInfoTextActivity.this);
        for (int i=0; i< informationTypeValues.size(); i++) {
            TrafficInfoTextEnum.InformationType type= informationTypeValues.get(i);
            if (selectedInformationTypeValuesPreferences.contains(type)) {
                defaultInformationValues[i] = true;
                selectedInformationTypes.add(type);
            } else {
                defaultInformationValues[i] = false;
            }
        }
        MultiSelectSpinner informationSpinner = (MultiSelectSpinner) findViewById(R.id.traffic_info_text_spinner_information);
        informationSpinner.setItems(
                Arrays.asList(getResources().getStringArray(R.array.traffic_info_text_criteria_spinner_values_information)),
                Arrays.asList(defaultInformationValues),
                getString(R.string.traffic_info_text_criteria_spinner_all_selected),
                getString(R.string.traffic_info_text_criteria_spinner_none_selected),
                getString(R.string.traffic_info_text_criteria_spinner_information_prompt),
                new MultiSelectSpinner.MultiSelectSpinnerListener() {
                    @Override
                    public void onItemsSelected(boolean[] selected) {
                        selectedInformationTypes.clear();
                        for (int i=0; i<selected.length; i++) {
                            if (selected[i]) {
                                selectedInformationTypes.add(informationTypeValues.get(i));
                            }
                        }
                        Preference.setSelectedTextInformationTypes(TrafficInfoTextActivity.this, selectedInformationTypes);
                    }
                }
        );

        //Region list
        regionValues = Arrays.asList(TrafficInfoTextEnum.Region.values());
        Boolean[] defaultRegionValues = new Boolean[regionValues.size()];
        List<TrafficInfoTextEnum.Region> selectedRegionValuesPreferences
                = Preference.getSelectedTextRegions(TrafficInfoTextActivity.this);
        for (int i=0; i<regionValues.size(); i++) {
            TrafficInfoTextEnum.Region region = regionValues.get(i);
            if (selectedRegionValuesPreferences.contains(region)) {
                defaultRegionValues[i] = true;
                selectedRegions.add(region);
            } else {
                defaultRegionValues[i] = false;
            }
        }
        MultiSelectSpinner regionSpinner = (MultiSelectSpinner) findViewById(R.id.traffic_info_text_spinner_region);
        regionSpinner.setItems(
                Arrays.asList(getResources().getStringArray(R.array.traffic_info_text_criteria_spinner_values_region)),
                Arrays.asList(defaultRegionValues),
                getString(R.string.traffic_info_text_criteria_spinner_all_selected),
                getString(R.string.traffic_info_text_criteria_spinner_none_selected),
                getString(R.string.traffic_info_text_criteria_spinner_region_prompt),
                new MultiSelectSpinner.MultiSelectSpinnerListener() {
                    @Override
                    public void onItemsSelected(boolean[] selected) {
                        selectedRegions.clear();
                        for (int i = 0; i < selected.length; i++) {
                            if (selected[i]) {
                                selectedRegions.add(regionValues.get(i));
                            }
                        }
                        Preference.setSelectedTextRegions(TrafficInfoTextActivity.this, selectedRegions);
                    }
                }
        );

        //Highroads list
        highroadValues = Arrays.asList(TrafficInfoTextEnum.Highroad.values());
        Boolean[] defaultHighroadValues = new Boolean[highroadValues.size()];
        List<TrafficInfoTextEnum.Highroad> selectedHighroadValuesPreferences
                = Preference.getSelectedTextHighroads(TrafficInfoTextActivity.this);
        for (int i=0; i< highroadValues.size(); i++) {
            TrafficInfoTextEnum.Highroad highroad = highroadValues.get(i);
            if (selectedHighroadValuesPreferences.contains(highroad)) {
                defaultHighroadValues[i] = true;
                selectedHighroads.add(highroad);
            } else {
                defaultHighroadValues[i] = false;
            }
        }
        MultiSelectSpinner highroadSpinner = (MultiSelectSpinner) findViewById(R.id.traffic_info_text_spinner_highroads);
        highroadSpinner.setItems(
                Arrays.asList(getResources().getStringArray(R.array.traffic_info_text_criteria_spinner_values_highroad)),
                Arrays.asList(defaultHighroadValues),
                getString(R.string.traffic_info_text_criteria_spinner_all_selected),
                getString(R.string.traffic_info_text_criteria_spinner_none_selected),
                getString(R.string.traffic_info_text_criteria_spinner_highroads_prompt),
                new MultiSelectSpinner.MultiSelectSpinnerListener() {
                    @Override
                    public void onItemsSelected(boolean[] selected) {
                        selectedHighroads.clear();
                        for (int i = 0; i < selected.length; i++) {
                            if (selected[i]) {
                                selectedHighroads.add(highroadValues.get(i));
                            }
                        }
                        Preference.setSelectedTextHighroads(TrafficInfoTextActivity.this, selectedHighroads);
                    }
                }
        );

        //Secondary roads list
        secondaryRoadValues = Arrays.asList(TrafficInfoTextEnum.SecondaryRoads.values());
        Boolean[] defaultSecondaryRoadValues = new Boolean[secondaryRoadValues.size()];
        List<TrafficInfoTextEnum.SecondaryRoads> selectedSecondaryRoadValuesPreferences
                = Preference.getSelectedTextSecondaryRoads(TrafficInfoTextActivity.this);
        for (int i=0; i< secondaryRoadValues.size(); i++) {
            TrafficInfoTextEnum.SecondaryRoads secondaryRoad = secondaryRoadValues.get(i);
            if (selectedSecondaryRoadValuesPreferences.contains(secondaryRoad)) {
                defaultSecondaryRoadValues[i] = true;
                selectedSecondaryRoads.add(secondaryRoad);
            } else {
                defaultSecondaryRoadValues[i] = false;
            }
        }
        MultiSelectSpinner secondaryRoadSpinner = (MultiSelectSpinner) findViewById(R.id.traffic_info_text_spinner_secondary_roads);
        secondaryRoadSpinner.setItems(
                Arrays.asList(getResources().getStringArray(R.array.traffic_info_text_criteria_spinner_values_secondary_road)),
                Arrays.asList(defaultSecondaryRoadValues),
                getString(R.string.traffic_info_text_criteria_spinner_all_selected),
                getString(R.string.traffic_info_text_criteria_spinner_none_selected),
                getString(R.string.traffic_info_text_criteria_spinner_secondary_roads_prompt),
                new MultiSelectSpinner.MultiSelectSpinnerListener() {
                    @Override
                    public void onItemsSelected(boolean[] selected) {
                        selectedSecondaryRoads.clear();
                        for (int i = 0; i < selected.length; i++) {
                            if (selected[i]) {
                                selectedSecondaryRoads.add(secondaryRoadValues.get(i));
                            }
                        }
                        Preference.setSelectedTextSecondaryRoads(TrafficInfoTextActivity.this, selectedSecondaryRoads);
                    }
                }
        );
    }

    private void attachButtons() {
        loadDataButton.setOnClickListener(new SearchAllOnClickListener());
    }
    
    private class SearchAllOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            TextView validationTextView = (TextView) findViewById(R.id.validation);
            if (selectedInformationTypes.size() == 0 ||
                    (selectedRegions.size() == 0 && selectedHighroads.size() == 0 && selectedSecondaryRoads.size() == 0) ) {
                validationTextView.setVisibility(View.VISIBLE);
                return;
            }
            validationTextView.setVisibility(View.GONE);
            loadDataTask = new LoadDataTask();
            loadDataTask.execute();
        }
    }

    private class LoadDataTask extends AsyncTask<Void, Void, List<TrafficInfoText>> {
        private ServiceException exception = null;
        
        @Override
        protected void onPreExecute() {
            loadDataButton.setEnabled(false);
            refreshButton.setVisibility(View.GONE);
            loadingWheel.setVisibility(View.VISIBLE);
        }

        @Override
        protected List<TrafficInfoText> doInBackground(Void... voids) {
            List<TrafficInfoText> items = new ArrayList<TrafficInfoText>();
            
            try {
                items = informationTextService.findByCriteria(
                        selectedInformationTypes, selectedRegions, selectedHighroads, selectedSecondaryRoads
                );
            } catch (ServiceException e) {
                exception = e;
            }
            
            return items;
        }

        @Override
        protected void onPostExecute(List<TrafficInfoText> informationItems) {
            loadDataButton.setEnabled(true);

            if (informationItems != null && informationItems.size() > 0) {
                Collections.sort(informationItems, new Comparator<TrafficInfoText>() {
                    @Override
                    public int compare(TrafficInfoText t1, TrafficInfoText t2) {
                        if (t1.getInformationType().equals(t2.getInformationType())) {
                            if (t1.getPublicationDate().before(t2.getPublicationDate())) {
                                return 1;
                            } else if (t1.getPublicationDate().after(t2.getPublicationDate())) {
                                return -1;
                            }
                        } else {
                            switch (t1.getInformationType()) {
                                case TRAFFIC_JAMS: {
                                    return -1;
                                }
                                case ACCIDENTS: {
                                    if (t2.getInformationType().equals(TrafficInfoTextEnum.InformationType.TRAFFIC_JAMS)) {
                                        return 1;
                                    } else {
                                        return -1;
                                    }
                                }
                                case ROAD_WORKS: {
                                    if (t2.getInformationType().equals(TrafficInfoTextEnum.InformationType.TRAFFIC_JAMS)
                                            || t2.getInformationType().equals(TrafficInfoTextEnum.InformationType.ACCIDENTS)) {
                                        return 1;
                                    } else {
                                        return -1;
                                    }
                                }
                                case TRAFFIC_INFO: {
                                    if (t2.getInformationType().equals(TrafficInfoTextEnum.InformationType.TRAFFIC_JAMS)
                                            || t2.getInformationType().equals(TrafficInfoTextEnum.InformationType.ACCIDENTS)
                                            || t2.getInformationType().equals(TrafficInfoTextEnum.InformationType.ROAD_WORKS)) {
                                        return 1;
                                    } else {
                                        return -1;
                                    }
                                }
                            }
                        }

                        return t1.getTitle().compareTo(t2.getTitle());
                    }
                });
                if (getListView().getAdapter() == null) {
                    TrafficInfoTextAdapter adapter = new TrafficInfoTextAdapter(
                            TrafficInfoTextActivity.this, informationItems, R.layout.list_item_traffic_info_text);
                    setListAdapter(adapter);
                } else {
                    ((TrafficInfoTextAdapter) getListView().getAdapter()).refill(informationItems);
                }

                getListView().setVisibility(View.VISIBLE);
            } else if (exception != null) {
                Toast.makeText(TrafficInfoTextActivity.this, R.string.exception_general_web_service, Toast.LENGTH_LONG).show();
            }

            loadingWheel.setVisibility(View.GONE);
            refreshButton.setVisibility(View.VISIBLE);

            if (exception == null && (informationItems == null || informationItems.size() == 0)) {
                getListView().setVisibility(View.GONE);

                AlertDialog.Builder builder = new AlertDialog.Builder(TrafficInfoTextActivity.this);
                builder.setTitle(R.string.traffic_info_text_list_no_data_found_title);
                builder.setMessage(R.string.traffic_info_text_list_no_data_found_msg);
                builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
                builder.show();
            }
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();

            loadingWheel.setVisibility(View.GONE);
            refreshButton.setVisibility(View.VISIBLE);

            Toast.makeText(TrafficInfoTextActivity.this, R.string.traffic_info_text_list_loading_canceled, Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        if (v.getId() == android.R.id.list) {
            super.onCreateContextMenu(menu, v, menuInfo);
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
            TrafficInfoText item = ((TrafficInfoTextAdapter) getListView().getAdapter()).getItem(info.position);

            menu.setHeaderTitle(R.string.traffic_info_text_list_context_menu_title);
            
            menu.add(Menu.NONE,
                    Constants.ContentMenuItems.SHARE,
                    Menu.NONE,
                    R.string.traffic_info_text_list_context_menu_option_share
            );
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
        TrafficInfoText trafficItem = ((TrafficInfoTextAdapter) getListView().getAdapter()).getItem(info.position);

        if (item.getItemId() == Constants.ContentMenuItems.SHARE) {
            List<TrafficInfoTextEnum.InformationType> typeValues = Arrays.asList(TrafficInfoTextEnum.InformationType.values());
            int typeIndex = typeValues.indexOf(trafficItem.getInformationType());
            CharSequence trafficType = TrafficInfoTextActivity.this.getResources()
                    .getTextArray(R.array.traffic_info_text_criteria_spinner_values_information)[typeIndex];
            String trafficItemText = getString(
                    R.string.traffic_info_text_list_context_menu_option_share_template, 
                    trafficType,
                    trafficItem.getTitle(),
                    getString(R.string.hashTag)
            );
            
            if (trafficItemText.length() > Constants.SHARE_TEXT_MAX_LENGTH) {
                int charsToMuch = trafficItemText.length() - Constants.SHARE_TEXT_MAX_LENGTH;
                String dots = getString(R.string.dots);
                int charsToRemove = charsToMuch + dots.length();

                String trafficItemTitle = trafficItem.getTitle().substring(0, trafficItem.getTitle().length() - charsToRemove);

                trafficItemText = getString(
                        R.string.traffic_info_text_list_context_menu_option_share_template,
                        trafficType,
                        trafficItemTitle,
                        getString(R.string.hashTag)
                );
            }
            
            Intent intent = new Intent(Intent.ACTION_SEND);
            intent.setType("text/plain");
            intent.putExtra(Intent.EXTRA_TEXT, trafficItemText.toString());
            startActivity(Intent.createChooser(intent, getText(R.string.traffic_info_text_list_context_menu_option_share_app_chooser)));
        }
        
        return true;
    }

    public void onHomeClick(View view) {
        IntentUtil.goHome(this);
    }

    public void onRefreshClick(View view) {
        loadDataTask = new LoadDataTask();
        loadDataTask.execute();
    }

    @Override
    public void finish() {
        if (loadDataTask != null) {
            loadDataTask.cancel(true);
        }
        super.finish();
    }
}
